home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.0 / stk-3 / blt-for-STk-3.0 / blt-1.9 / src / bltGrMisc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-01  |  23.8 KB  |  861 lines

  1.  
  2. /*
  3.  * bltGrMisc.c --
  4.  *
  5.  *    This module implements a graph widget for the
  6.  *    Tk toolkit.
  7.  *
  8.  * Copyright 1991-1994 by AT&T Bell Laboratories.
  9.  * Permission to use, copy, modify, and distribute this software
  10.  * and its documentation for any purpose and without fee is hereby
  11.  * granted, provided that the above copyright notice appear in all
  12.  * copies and that both that the copyright notice and warranty
  13.  * disclaimer appear in supporting documentation, and that the
  14.  * names of AT&T Bell Laboratories any of their entities not be used
  15.  * in advertising or publicity pertaining to distribution of the
  16.  * software without specific, written prior permission.
  17.  *
  18.  * AT&T disclaims all warranties with regard to this software, including
  19.  * all implied warranties of merchantability and fitness.  In no event
  20.  * shall AT&T be liable for any special, indirect or consequential
  21.  * damages or any damages whatsoever resulting from loss of use, data
  22.  * or profits, whether in an action of contract, negligence or other
  23.  * tortuous action, arising out of or in connection with the use or
  24.  * performance of this software.
  25.  *
  26.  */
  27.  
  28. #include "blt.h"
  29. #include "bltGraph.h"
  30. #include <X11/Xutil.h>
  31.  
  32. extern int strcasecmp _ANSI_ARGS_((CONST char *s1, CONST char *s2));
  33.  
  34. static int ParsePosition _ANSI_ARGS_((ClientData, Tcl_Interp *, Tk_Window,
  35.     char *, char *, int));
  36. static char *PrintPosition _ANSI_ARGS_((ClientData, Tk_Window, char *, int,
  37.     Tcl_FreeProc **));
  38.  
  39. Tk_CustomOption bltPositionOption =
  40. {
  41.     ParsePosition, PrintPosition, (ClientData)0
  42. };
  43.  
  44. static int ParseAxisFlags _ANSI_ARGS_((ClientData, Tcl_Interp *, Tk_Window,
  45.     char *, char *, int));
  46. static char *PrintAxisFlags _ANSI_ARGS_((ClientData, Tk_Window, char *, int,
  47.     Tcl_FreeProc **));
  48.  
  49. Tk_CustomOption bltXAxisFlagsOption =
  50. {
  51.     ParseAxisFlags, PrintAxisFlags, (ClientData)ANY_X_MASK
  52. };
  53.  
  54. Tk_CustomOption bltYAxisFlagsOption =
  55. {
  56.     ParseAxisFlags, PrintAxisFlags, (ClientData)ANY_Y_MASK
  57. };
  58.  
  59.  
  60. /* ----------------------------------------------------------------------
  61.  * Custom option parse and print procedures
  62.  * ----------------------------------------------------------------------
  63.  */
  64.  
  65. int
  66. Blt_GetPosition(interp, string, pointPtr)
  67.     Tcl_Interp *interp;
  68.     char *string;
  69.     XPoint *pointPtr;
  70. {
  71.     char *strX, *strY;
  72.     int x, y;
  73.  
  74.     if ((string == NULL) || (*string == '\0')) {
  75.     pointPtr->y = pointPtr->x = DEF_POSITION;
  76.     return TCL_OK;        /* Position marked as default */
  77.     }
  78.     if (*string != '@') {
  79.     Tcl_AppendResult(interp, "bad position \"", string,
  80.         "\": must start with an '@'", (char *)NULL);
  81.     return TCL_ERROR;
  82.     }
  83.     strX = string + 1;
  84.     strY = strchr(strX, ',');
  85.     if (strY == NULL) {
  86.     Tcl_AppendResult(interp, "bad position \"", string,
  87.         "\": should be \"@x,y\"", (char *)NULL);
  88.     return TCL_ERROR;
  89.     }
  90.     *strY++ = '\0';
  91.     if ((Tcl_GetInt(interp, strX, &x) != TCL_OK) ||
  92.     (Tcl_GetInt(interp, strY, &y) != TCL_OK)) {
  93.     return TCL_ERROR;
  94.     }
  95.     pointPtr->x = x, pointPtr->y = y;
  96.     return TCL_OK;
  97. }
  98.  
  99. /*
  100.  *----------------------------------------------------------------------
  101.  *
  102.  * ParsePosition --
  103.  *
  104.  *    Convert the string representation of a legend XY position into
  105.  *    window coordinates.  The form of the string must be "@x,y" or
  106.  *    none.
  107.  *
  108.  * Results:
  109.  *    The return value is a standard Tcl result.  The symbol type is
  110.  *    written into the widget record.
  111.  *
  112.  * Side Effects:
  113.  *    If no legend position is given, the right margin of the graph
  114.  *    will be automatically increased to hold the legend.
  115.  *
  116.  *----------------------------------------------------------------------
  117.  */
  118. /*ARGSUSED*/
  119. static int
  120. ParsePosition(clientData, interp, tkwin, value, widgRec, offset)
  121.     ClientData clientData;    /* not used */
  122.     Tcl_Interp *interp;        /* Interpreter to send results back to */
  123.     Tk_Window tkwin;        /* not used */
  124.     char *value;        /* New legend position string */
  125.     char *widgRec;        /* Widget record */
  126.     int offset;            /* offset to XPoint structure */
  127. {
  128.     XPoint *pointPtr = (XPoint *)(widgRec + offset);
  129.     return (Blt_GetPosition(interp, value, pointPtr));
  130. }
  131.  
  132. /*
  133.  *----------------------------------------------------------------------
  134.  *
  135.  * PrintPosition --
  136.  *
  137.  *    Convert the window coordinates into a string.
  138.  *
  139.  * Results:
  140.  *    The string representing the coordinate position is returned.
  141.  *
  142.  *----------------------------------------------------------------------
  143.  */
  144. /*ARGSUSED*/
  145. static char *
  146. PrintPosition(clientData, tkwin, widgRec, offset, freeProcPtr)
  147.     ClientData clientData;    /* not used */
  148.     Tk_Window tkwin;        /* not used */
  149.     char *widgRec;        /* Widget record */
  150.     int offset;            /* offset of XPoint in record */
  151.     Tcl_FreeProc **freeProcPtr;    /* Memory deallocation scheme to use */
  152. {
  153.     char *result;
  154.     XPoint *pointPtr = (XPoint *)(widgRec + offset);
  155.  
  156.     result = "";
  157.     if (pointPtr->x != DEF_POSITION) {
  158.     char string[200];
  159.  
  160.     sprintf(string, "@%d,%d", pointPtr->x, pointPtr->y);
  161.     result = strdup(string);
  162.     if (result == NULL) {
  163.         return (strerror(errno));
  164.     }
  165.     *freeProcPtr = (Tcl_FreeProc *)free;
  166.     }
  167.     return (result);
  168. }
  169.  
  170. /*
  171.  *----------------------------------------------------------------------
  172.  *
  173.  * ParseAxisFlags --
  174.  *
  175.  *    Convert the string indicating which axis flags to use.
  176.  *
  177.  * Results:
  178.  *    The return value is a standard Tcl result.  The axis flags are
  179.  *    written into the widget record.
  180.  *
  181.  *----------------------------------------------------------------------
  182.  */
  183. /*ARGSUSED*/
  184. static int
  185. ParseAxisFlags(clientData, interp, tkwin, value, widgRec, offset)
  186.     ClientData clientData;    /* not used */
  187.     Tcl_Interp *interp;        /* Interpreter to send results back to */
  188.     Tk_Window tkwin;        /* not used */
  189.     char *value;        /* Axis type */
  190.     char *widgRec;        /* Widget record */
  191.     int offset;            /* offset of AxisType field */
  192. {
  193.     int *flagsPtr = (int *)(widgRec + offset);
  194.     int mask = (int)clientData;
  195.     int flags;
  196.  
  197.     flags = 0;
  198.     if (mask == ANY_X_MASK) {
  199.     if (strcmp(value, "x2") == 0) {
  200.         flags = X2_AXIS_MASK;
  201.     } else if (strcmp(value, "x1") == 0) {
  202.         flags = X1_AXIS_MASK;
  203.     } else if (strcmp(value, "x") == 0) {
  204.         flags = X1_AXIS_MASK;
  205.     } else if (strcmp(value, "both") == 0) {
  206.         flags = (X1_AXIS_MASK | X2_AXIS_MASK);
  207.     } else {
  208.         Tcl_AppendResult(interp, "bad x-axis type \"", value,
  209.         "\": should be x or x2", (char *)NULL);
  210.         return TCL_ERROR;
  211.     }
  212.     } else {
  213.     if (strcmp(value, "y2") == 0) {
  214.         flags = Y2_AXIS_MASK;
  215.     } else if (strcmp(value, "y1") == 0) {
  216.         flags = Y1_AXIS_MASK;
  217.     } else if (strcmp(value, "y") == 0) {
  218.         flags = Y1_AXIS_MASK;
  219.     } else if (strcmp(value, "both") == 0) {
  220.         flags = (Y1_AXIS_MASK | Y2_AXIS_MASK);
  221.     } else {
  222.         Tcl_AppendResult(interp, "bad y-axis type \"", value,
  223.         "\": should be y or y2", (char *)NULL);
  224.         return TCL_ERROR;
  225.     }
  226.     }
  227.     *flagsPtr &= ~mask;
  228.     *flagsPtr |= flags;
  229.     return TCL_OK;
  230. }
  231.  
  232. /*
  233.  *----------------------------------------------------------------------
  234.  *
  235.  * PrintAxisFlags --
  236.  *
  237.  *    Convert the window coordinates into a string.
  238.  *
  239.  * Results:
  240.  *    The string representing the coordinate position is returned.
  241.  *
  242.  *----------------------------------------------------------------------
  243.  */
  244. /*ARGSUSED*/
  245. static char *
  246. PrintAxisFlags(clientData, tkwin, widgRec, offset, freeProcPtr)
  247.     ClientData clientData;    /* not used */
  248.     Tk_Window tkwin;        /* not used */
  249.     char *widgRec;        /* Widget record */
  250.     int offset;            /* offset of AxisType field */
  251.     Tcl_FreeProc **freeProcPtr;    /* not used */
  252. {
  253.     char *result;
  254.     int flags = *(int *)(widgRec + offset);
  255.     int mask = (int)clientData;
  256.  
  257.     flags &= mask;
  258.     result = "";
  259.     if ((flags == ANY_X_MASK) || (flags == ANY_Y_MASK)) {
  260.     result = "both";
  261.     } else if (flags & X1_AXIS_MASK) {
  262.     result = "x";
  263.     } else if (flags & X2_AXIS_MASK) {
  264.     result = "x2";
  265.     } else if (flags & Y1_AXIS_MASK) {
  266.     result = "y";
  267.     } else if (flags & Y2_AXIS_MASK) {
  268.     result = "y2";
  269.     }
  270.     return (result);
  271. }
  272.  
  273. /*-----------------------------------------------------------------
  274.  * X-related drawing routines
  275.  * -----------------------------------------------------------------
  276.  */
  277.  
  278. /*
  279.  * -----------------------------------------------------------------
  280.  *
  281.  * Blt_TextStringWidth
  282.  *
  283.  *    Returns the width in pixels of a text string.
  284.  *
  285.  * -----------------------------------------------------------------
  286.  */
  287. unsigned int
  288. Blt_TextStringWidth(fontPtr, text)
  289.     XFontStruct *fontPtr;    /* Font information */
  290.     char *text;            /* Text string */
  291. {
  292.     XCharStruct bbox;        /* Bounding box for text string */
  293.     int dummy;            /* not used */
  294.  
  295.     /* Get the width and height of the text string to be created */
  296.  
  297.     XTextExtents(fontPtr, text, strlen(text), &dummy, &dummy, &dummy, &bbox);
  298.     return (bbox.rbearing + bbox.lbearing);
  299. }
  300.  
  301. /*
  302.  * -----------------------------------------------------------------
  303.  *
  304.  * Blt_TranslateTextCoords --
  305.  *
  306.  *     Translate the coordinates of a given text string based upon
  307.  *    the anchor specified.  The anchor indicates where the given
  308.  *    xy position are in relation to the text bounding box.
  309.  *
  310.  *          nw --- n --- ne
  311.  *          |            |
  312.  *          w   center   e
  313.  *          |            |
  314.  *          sw --- s --- se
  315.  *
  316.  *     The coordinates returned are translated to the baseline
  317.  *     origin of the text bounding box (suitable for giving to
  318.  *     XDrawString, XDrawText, etc).
  319.  *
  320.  * Results:
  321.  *    The translated text coordinates are returned.
  322.  *
  323.  * -----------------------------------------------------------------
  324.  */
  325. XPoint
  326. Blt_TranslateTextCoords(fontPtr, text, x, y, anchor)
  327.     XFontStruct *fontPtr;    /* Font information */
  328.     char *text;            /* Text string */
  329.     int x, y;            /* Position of anchor */
  330.     Tk_Anchor anchor;        /* Direction of the anchor */
  331. {
  332.     int width;
  333.     XPoint newPt;
  334.  
  335.     /*
  336.      * Get the width the text string to be created. Height is assumed to be
  337.      * the sum of font ascent and descent.
  338.      */
  339.  
  340.     width = Blt_TextStringWidth(fontPtr, text);
  341.  
  342.     newPt.x = x, newPt.y = y;
  343.     switch (anchor) {
  344.     case TK_ANCHOR_NW:
  345.     newPt.y += fontPtr->ascent;
  346.     break;
  347.     case TK_ANCHOR_W:
  348.     newPt.y += (fontPtr->ascent - fontPtr->descent) / 2;
  349.     break;
  350.     case TK_ANCHOR_SW:
  351.     newPt.y -= fontPtr->descent;
  352.     break;
  353.     case TK_ANCHOR_NE:
  354.     newPt.x -= width;
  355.     newPt.y += fontPtr->ascent;
  356.     break;
  357.     case TK_ANCHOR_E:
  358.     newPt.x -= width;
  359.     newPt.y += (fontPtr->ascent - fontPtr->descent) / 2;
  360.     break;
  361.     case TK_ANCHOR_SE:
  362.     newPt.x -= width;
  363.     newPt.y -= fontPtr->descent;
  364.     break;
  365.     case TK_ANCHOR_N:
  366.     newPt.y += fontPtr->ascent;
  367.     newPt.x -= width / 2;
  368.     break;
  369.     case TK_ANCHOR_S:
  370.     newPt.y -= fontPtr->descent;
  371.     newPt.x -= width / 2;
  372.     break;
  373.     case TK_ANCHOR_CENTER:
  374.     newPt.x -= width / 2;
  375.     newPt.y += (fontPtr->ascent - fontPtr->descent) / 2;
  376.     break;
  377.     }
  378.     return (newPt);
  379. }
  380.  
  381. /*
  382.  * -----------------------------------------------------------------
  383.  *
  384.  * Blt_GetBoundingBox
  385.  *
  386.  *     Computes the size the bounding box of a rotated rectangle, given
  387.  *    by the width, height, and rotation.  The rectangle corners are
  388.  *    simply rotated and the min and max x,y coordinates are determined.
  389.  *      The rectangle is centered at 0,0.  Point 0 is at -w/2, -h/2.
  390.  *    Point 1 is at w/2, -h/2, etc.
  391.  *
  392.  *          0 ------- 1
  393.  *          |         |
  394.  *          |    x    |
  395.  *          |         |
  396.  *          3 ------- 2
  397.  *
  398.  * Results:
  399.  *    The width and height of the bounding box containing the
  400.  *    rotated rectangle are returned.
  401.  *
  402.  * -----------------------------------------------------------------
  403.  */
  404. void
  405. Blt_GetBoundingBox(width, height, theta, rotWPtr, rotHPtr, pointArr)
  406.     unsigned int width, height;    /* Unrotated region */
  407.     double theta;        /* Rotation of box */
  408.     unsigned int *rotWPtr, *rotHPtr;    /* Rotated bounding box region */
  409.     XPoint *pointArr;        /* Points of the rotated box */
  410. {
  411.     register int i;
  412.     double sinTheta, cosTheta;
  413.     double maxX, maxY;
  414.     register double x, y;
  415.     struct Coord {
  416.     double x, y;
  417.     } corner[4];
  418.  
  419.     /*
  420.      * Set the four corners of the rectangle whose center is the origin
  421.      */
  422.  
  423.     corner[1].x = corner[2].x = width * 0.5;
  424.     corner[0].x = corner[3].x = -corner[1].x;
  425.     corner[2].y = corner[3].y = height * 0.5;
  426.     corner[0].y = corner[1].y = -corner[2].y;
  427.  
  428.     theta = (-theta / 180.0) * M_PI;
  429.     sinTheta = sin(theta), cosTheta = cos(theta);
  430.     maxX = maxY = 0.0;
  431.  
  432.     /*
  433.      * Rotate the four corners and find the maximum X and Y coordinates
  434.      */
  435.  
  436.     for (i = 0; i < 4; i++) {
  437.     x = (corner[i].x * cosTheta) - (corner[i].y * sinTheta);
  438.     y = (corner[i].x * sinTheta) + (corner[i].y * cosTheta);
  439.     if (x > maxX) {
  440.         maxX = x;
  441.     }
  442.     if (y > maxY) {
  443.         maxY = y;
  444.     }
  445.     if (pointArr != NULL) {
  446.         pointArr[i].x = BLT_RND(x);
  447.         pointArr[i].y = BLT_RND(y);
  448.     }
  449.     }
  450.  
  451.     /*
  452.      * By symmetry, the width and height of the bounding box are
  453.      * twice the maximum x and y coordinates.
  454.      */
  455.  
  456.     *rotWPtr = (int)((maxX + maxX) + 0.5);
  457.     *rotHPtr = (int)((maxY + maxY) + 0.5);
  458. }
  459.  
  460. /*
  461.  * -----------------------------------------------------------------
  462.  *
  463.  * Blt_TranslateBoxCoords --
  464.  *
  465.  *     Translate the coordinates of a given bounding box based
  466.  *    upon the anchor specified.  The anchor indicates where
  467.  *    the given xy position is in relation to the bounding box.
  468.  *
  469.  *          nw --- n --- ne
  470.  *          |            |
  471.  *          w   center   e
  472.  *          |            |
  473.  *          sw --- s --- se
  474.  *
  475.  *     The coordinates returned are translated to the origin of the
  476.  *     bounding box (suitable for giving to XCopyArea, etc.)
  477.  *
  478.  * Results:
  479.  *    The translated coordinates of the bounding box are returned.
  480.  *
  481.  * -----------------------------------------------------------------
  482.  */
  483. XPoint
  484. Blt_TranslateBoxCoords(x, y, width, height, anchor)
  485.     int x, y;            /* Window coordinates of anchor */
  486.     unsigned int width, height;    /* Extents of the bounding box */
  487.     Tk_Anchor anchor;        /* Direction of the anchor */
  488. {
  489.     XPoint newPt;
  490.  
  491.     newPt.x = x, newPt.y = y;
  492.     switch (anchor) {
  493.     case TK_ANCHOR_NW:        /* Upper left corner */
  494.     break;
  495.     case TK_ANCHOR_W:        /* Left center */
  496.     newPt.y -= (height / 2);
  497.     break;
  498.     case TK_ANCHOR_SW:        /* Lower left corner */
  499.     newPt.y -= height;
  500.     break;
  501.     case TK_ANCHOR_N:        /* Top center */
  502.     newPt.x -= (width / 2);
  503.     break;
  504.     case TK_ANCHOR_CENTER:    /* Centered */
  505.     newPt.x -= (width / 2);
  506.     newPt.y -= (height / 2);
  507.     break;
  508.     case TK_ANCHOR_S:        /* Bottom center */
  509.     newPt.x -= (width / 2);
  510.     newPt.y -= height;
  511.     break;
  512.     case TK_ANCHOR_NE:        /* Upper right corner */
  513.     newPt.x -= width;
  514.     break;
  515.     case TK_ANCHOR_E:        /* Right center */
  516.     newPt.x -= width;
  517.     newPt.y -= (height / 2);
  518.     break;
  519.     case TK_ANCHOR_SE:        /* Lower right corner */
  520.     newPt.x -= width;
  521.     newPt.y -= height;
  522.     break;
  523.     }
  524.     return (newPt);
  525. }
  526.  
  527. /*
  528.  * -----------------------------------------------------------------
  529.  *
  530.  * Blt_RotateBitmap --
  531.  *
  532.  *    Creates a new bitmap containing the rotated image of the given
  533.  *    bitmap.  We also need a special GC of depth 1, so that we do
  534.  *    not need to rotate more than one plane of the bitmap.
  535.  *
  536.  * Results:
  537.  *    Returns a new bitmap containing the rotated image.
  538.  *
  539.  * -----------------------------------------------------------------
  540.  */
  541. Pixmap
  542. Blt_RotateBitmap(display, draw, bitmapGC, srcBitmap, srcWidth, srcHeight,
  543.     theta, rotWPtr, rotHPtr)
  544.     Display *display;        /* X display */
  545.     Drawable draw;        /* Root window drawable */
  546.     GC bitmapGC;        /* GC created from bitmap where fg=1,bg=0 */
  547.     Pixmap srcBitmap;        /* Source bitmap to be rotated */
  548.     unsigned int srcWidth;    /* Width and height of the source bitmap */
  549.     unsigned int srcHeight;
  550.     double theta;        /* Right angle rotation to perform */
  551.     unsigned int *rotWPtr, *rotHPtr;
  552. {
  553.     XImage *src, *dest;
  554.     Pixmap destBitmap;
  555.     unsigned int destWidth, destHeight;
  556.     register int dx, dy;    /* Destination bitmap coordinates */
  557.     register int sx, sy;    /* Source bitmap coordinates */
  558.     double transX, transY;
  559.     double rotX, rotY;
  560.     double radians, sinTheta, cosTheta;
  561.     unsigned long pixel;
  562.     double srcX, srcY;        /* Center of source rectangle */
  563.     double destX, destY;    /* Center of destination rectangle */
  564.  
  565.     /*
  566.      * Create a bitmap and image big enough to contain the rotated text
  567.      */
  568.  
  569.     Blt_GetBoundingBox(srcWidth, srcHeight, theta, &destWidth, &destHeight,
  570.     (XPoint *)NULL);
  571.     destBitmap = XCreatePixmap(display, draw, destWidth, destHeight, 1);
  572.     XSetForeground(display, bitmapGC, 0x0);
  573.     XFillRectangle(display, destBitmap, bitmapGC, 0, 0, destWidth, destHeight);
  574.     src = XGetImage(display, srcBitmap, 0, 0, srcWidth, srcHeight, 1, ZPixmap);
  575.     dest = XGetImage(display, destBitmap, 0, 0, destWidth, destHeight, 1,
  576.     ZPixmap);
  577.     radians = (theta / 180.0) * M_PI;
  578.     sinTheta = sin(radians), cosTheta = cos(radians);
  579.     /*
  580.      * Coordinates of the centers of the source and destination rectangles
  581.      */
  582.     srcX = srcWidth * 0.5;
  583.     srcY = srcHeight * 0.5;
  584.     destX = destWidth * 0.5;
  585.     destY = destHeight * 0.5;
  586.     /*
  587.      * Rotate each pixel of dest image, placing results in source image
  588.      */
  589.     for (dx = 0; dx < destWidth; dx++) {
  590.     for (dy = 0; dy < destHeight; dy++) {
  591.         if (theta == 270.0) {
  592.         sx = dy, sy = destWidth - dx - 1;
  593.         } else if (theta == 180.0) {
  594.         sx = destWidth - dx - 1, sy = destHeight - dy - 1;
  595.         } else if (theta == 90.0) {
  596.         sx = destHeight - dy - 1, sy = dx;
  597.         } else if (theta == 0.0) {
  598.         sx = dx, sy = dy;
  599.         } else {
  600.  
  601.         /* Translate origin to center of destination image */
  602.  
  603.         transX = dx - destX;
  604.         transY = dy - destY;
  605.  
  606.         /* Rotate the coordinates about the origin */
  607.  
  608.         rotX = (transX * cosTheta) - (transY * sinTheta);
  609.         rotY = (transX * sinTheta) + (transY * cosTheta);
  610.  
  611.         /* Translate back to the center of the source image */
  612.         rotX += srcX;
  613.         rotY += srcY;
  614.  
  615.         sx = BLT_RND(rotX);
  616.         sy = BLT_RND(rotY);
  617.  
  618.         /*
  619.          * Verify the coordinates, since the destination image can be
  620.          * bigger than the source
  621.          */
  622.  
  623.         if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) ||
  624.             (sy < 0)) {
  625.             continue;
  626.         }
  627.         }
  628.         pixel = XGetPixel(src, sx, sy);
  629.         if (pixel) {
  630.         XPutPixel(dest, dx, dy, pixel);
  631.         }
  632.     }
  633.     }
  634.  
  635.     /* Write the rotated image into the destination bitmap */
  636.  
  637.     XPutImage(display, destBitmap, bitmapGC, dest, 0, 0, 0, 0, destWidth,
  638.     destHeight);
  639.  
  640.     /* Clean up temporary resources used */
  641.  
  642.     XDestroyImage(src), XDestroyImage(dest);
  643.     *rotWPtr = destWidth;
  644.     *rotHPtr = destHeight;
  645.     return (destBitmap);
  646. }
  647.  
  648. /*
  649.  * -----------------------------------------------------------------
  650.  *
  651.  * Blt_CreateTextBitmap --
  652.  *
  653.  *    Draw a bitmap, using the the given window coordinates
  654.  *    as an anchor for the text bounding box.
  655.  *
  656.  * Results:
  657.  *    Returns the bitmap representing the text string.
  658.  *
  659.  * Side Effects:
  660.  *    Bitmap is drawn using the given font and GC on the graph
  661.  *    window at the given coordinates, anchor, and rotation.
  662.  *
  663.  * -----------------------------------------------------------------
  664.  */
  665. Pixmap
  666. Blt_CreateTextBitmap(display, draw, fontPtr, text, theta, widthPtr, heightPtr)
  667.     Display *display;
  668.     Drawable draw;
  669.     XFontStruct *fontPtr;    /* Font to draw bitmap */
  670.     char *text;            /* Text string to draw */
  671.     double theta;        /* Desired rotation of bitmap */
  672.     unsigned int *widthPtr, *heightPtr;    /* Height of text bitmap */
  673. {
  674.     unsigned int width, height;    /* Width and height of text bounding box */
  675.     Pixmap bitmap;
  676.     XGCValues gcValues;
  677.     unsigned long gcMask;
  678.     GC bitmapGC;
  679.     int numChar;        /* Size of text string */
  680.  
  681.     numChar = strlen(text);
  682.  
  683.     /*
  684.      * Determine the width and height of the text bitmap to be created
  685.      */
  686.  
  687.     width = Blt_TextStringWidth(fontPtr, text);
  688.     height = (unsigned int)TEXTHEIGHT(fontPtr);
  689.  
  690.     /*
  691.      * Create a temporary bitmap and draw the text string into it
  692.      */
  693.  
  694.     bitmap = XCreatePixmap(display, draw, width, height, 1);
  695.     gcValues.font = fontPtr->fid;
  696.     gcValues.foreground = gcValues.background = 0;
  697.     gcMask = (GCFont | GCForeground | GCBackground);
  698.     bitmapGC = XCreateGC(display, bitmap, gcMask, &gcValues);
  699.  
  700.     /*
  701.      * Clear the bitmap before drawing the text string into it.
  702.      * (XDrawImageString is unreliable to draw all bits)
  703.      */
  704.  
  705.     XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
  706.     XSetForeground(display, bitmapGC, 1);
  707.     XDrawString(display, bitmap, bitmapGC, 0, fontPtr->ascent, text, numChar);
  708.     if (theta == 0.0) {
  709.     *widthPtr = width, *heightPtr = height;
  710.     } else {
  711.     Pixmap rotBitmap;
  712.  
  713.     rotBitmap = Blt_RotateBitmap(display, draw, bitmapGC, bitmap, width,
  714.         height, theta, widthPtr, heightPtr);
  715.     XFreePixmap(display, bitmap);
  716.     bitmap = rotBitmap;
  717.     }
  718.     XFreeGC(display, bitmapGC);
  719.     return (bitmap);
  720. }
  721.  
  722. /*
  723.  * -----------------------------------------------------------------
  724.  *
  725.  * Blt_StencilBitmap --
  726.  *
  727.  *    Stencil (draw foreground only) a bitmap at the given window
  728.  *      coordinates.  This routine should be used sparingly since it
  729.  *      is very slow on most X servers.
  730.  *
  731.  *      Please note:  This routine assumes that the GC is NOT shared,
  732.  *     since it will change the FillStyle and TSOrigin fields of the GC.
  733.  *
  734.  * Results:
  735.  *    None.
  736.  *
  737.  * Side Effects:
  738.  *    Bitmap is stenciled on the graph window at the given coordinates.
  739.  * -----------------------------------------------------------------
  740.  */
  741. void
  742. Blt_StencilBitmap(display, draw, gc, bitmap, x, y, width, height)
  743.     Display *display;
  744.     Drawable draw;
  745.     GC gc;            /* Graphic context to use */
  746.     Pixmap bitmap;        /* Bitmap to be displayed */
  747.     int x, y;            /* x, y position of bitmap */
  748.     unsigned int width, height;
  749. {
  750.     XSetStipple(display, gc, bitmap);
  751.     XSetTSOrigin(display, gc, x, y);
  752.     XSetFillStyle(display, gc, FillStippled);
  753.     XFillRectangle(display, draw, gc, x, y, width, height);
  754. }
  755.  
  756. /*
  757.  * -----------------------------------------------------------------
  758.  *
  759.  * Blt_DrawText --
  760.  *
  761.  *    Draw a text string, possibly rotated,  using the the given
  762.  *    window coordinates as an anchor for the text bounding box.
  763.  *
  764.  *      Please note:  This routine assumes that for rotated (not
  765.  *    right angles) text the GC is NOT shared, since Blt_StencilBitmap
  766.  *    will change the FillStyle and TSOrigin fields of the GC.
  767.  *
  768.  * Results:
  769.  *    None.
  770.  *
  771.  * Side Effects:
  772.  *    Text string is drawn using the given font and GC on the
  773.  *    graph window at the given coordinates, anchor, and rotation
  774.  * -----------------------------------------------------------------
  775.  */
  776. void
  777. Blt_DrawText(display, draw, text, attrPtr, x, y)
  778.     Display *display;
  779.     Drawable draw;
  780.     char *text;
  781.     TextAttributes *attrPtr;    /* Text attribute information */
  782.     int x;            /* Window x coordinate */
  783.     int y;            /* Window y coordinate */
  784. {
  785.     XPoint win;
  786.  
  787.     if ((text == NULL) || (*text == '\0')) {    /* Empty string, do nothing */
  788.     return;
  789.     }
  790.     if (attrPtr->theta == 0.0) {/* No rotation. Handle simple case */
  791.     int textLength = strlen(text);
  792.  
  793.     win = Blt_TranslateTextCoords(attrPtr->fontPtr, text, x, y,
  794.         attrPtr->anchor);
  795.     XDrawString(display, draw, attrPtr->gc, win.x, win.y,
  796.         text, textLength);
  797.     } else {
  798.     Pixmap bitmap;
  799.     unsigned int bmWidth, bmHeight;
  800.  
  801.     /* Create rotated bitmap of text string */
  802.  
  803.     bitmap = Blt_CreateTextBitmap(display, draw, attrPtr->fontPtr, text,
  804.         attrPtr->theta, &bmWidth, &bmHeight);
  805.     win = Blt_TranslateBoxCoords(x, y, bmWidth, bmHeight,
  806.         attrPtr->anchor);
  807.     if ((attrPtr->theta == 90.0) || (attrPtr->theta == 180.0) ||
  808.         (attrPtr->theta == 270.0)) {
  809.         XCopyPlane(display, bitmap, draw, attrPtr->gc, 0, 0, bmWidth,
  810.         bmHeight, win.x, win.y, 1);
  811.     } else {
  812.         Blt_StencilBitmap(display, draw, attrPtr->gc, bitmap,
  813.         win.x, win.y, bmWidth, bmHeight);
  814.     }
  815.     XFreePixmap(display, bitmap);
  816.     }
  817. }
  818.  
  819. /*
  820.  * -----------------------------------------------------------------
  821.  *
  822.  * Blt_FindToken --
  823.  *
  824.  *    Linearly search through a list of strings.  Returns the
  825.  *      the index of *key*.
  826.  *
  827.  * Results:
  828.  *    Returns index of *key* if found, -1 otherwise.
  829.  *
  830.  * -----------------------------------------------------------------
  831.  */
  832.  
  833. int
  834. Blt_GetTokenIndex(tokenList, key, ignoreCase)
  835.     char **tokenList;
  836.     char *key;
  837.     int ignoreCase;
  838. {
  839.     int length;
  840.     register int count;
  841.     register char **p;
  842.     int found;
  843.     char c;
  844.  
  845.     length = strlen(key);
  846.     count = 0;
  847.     c = *key;
  848.     for (p = tokenList; *p != NULL; p++) {
  849.     if (ignoreCase) {
  850.         found = (strncasecmp(key, *p, length) == 0);
  851.     } else {
  852.         found = ((c == **p) && (strncmp(key, *p, length) == 0));
  853.     }
  854.     if (found) {
  855.         return (count);
  856.     }
  857.     count++;
  858.     }
  859.     return -1;
  860. }
  861.